﻿// Copyright (c) egmkang wang. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using XServer.SDK;

namespace XServer.Config
{
    using System;
    using System.Collections.Generic;
    using System.Collections.Concurrent;
    using XServer.SDK;

    public interface ISwapable
    {
        void Check();
        void Swap();
    }

    public class ConfigManager<TConfig, TKey> : ISwapable
        where TConfig : IConfig<TKey>
    {
        ConcurrentDictionary<TKey, Handle<TConfig>> dict = new ConcurrentDictionary<TKey, Handle<TConfig>>();
        ConcurrentDictionary<TKey, Handle<TConfig>> temp = new ConcurrentDictionary<TKey, Handle<TConfig>>();

        public ConfigManager()
        {
            var set = Singleton<HashSet<ISwapable>>.Instance;
            if (set.Contains(this))
            {
                return;
            }
            set.Add(this);
        }

        public Handle<TConfig> Get(TKey id)
        {
            Handle<TConfig> ret = null;
            this.dict.TryGetValue(id, out ret);
            return ret;
        }

        public Handle<TConfig> GetTemp(TKey id)
        {
            Handle<TConfig> ret = null;
            this.temp.TryGetValue(id, out ret);
            return ret;
        }

        public void Add(TConfig config)
        {
            var id = config.ID;
            Handle<TConfig> h = this.GetTemp(id);
            if (h != null)
            {
                h.Value = config;
            }
            else
            {
                h = new Handle<TConfig>(config);
                this.temp.TryAdd(config.ID, h);
            }
        }

        public void Swap()
        {
            if (this.temp.Count == 0)
            {
                return;
            }
            foreach (var item in this.dict)
            {
                var h = this.Get(item.Key);
                if (h != null)
                {
                    h.Value = item.Value.Value;
                }
            }
            this.dict = this.temp;
            this.temp = temp = new ConcurrentDictionary<TKey, Handle<TConfig>>();
        }

        public void Check()
        {
            var error = 0;
            foreach (var pair in this.temp)
            {
                error += pair.Value.Value.CheckError() ? 1 : 0;
            }
            if (error > 0)
            {
                this.temp.Clear();
                LoggerProvider.Logger.Error("LoadConfig {0} ErrorCount:{1}", typeof(TConfig).Name, error);
            }
        }
    }

    public class Config
    {
        public static Handle<TConfig> Get<TConfig>(int key)
            where TConfig : IConfigWithIntKey
        {
            return Singleton<ConfigManager<TConfig, int>>.Instance.Get(key);
        }

        public static Handle<TConfig> Get<TConfig>(string key)
            where TConfig : IConfigWithStringKey
        {
            return Singleton<ConfigManager<TConfig, string>>.Instance.Get(key);
        }
    }
}
